import enum
from csv import reader
from math import e


class InsType(enum.Enum):
    Ins_Undef = -1
    Ins_R = 0
    Ins_I = 1


Commands: dict[str, tuple[int, int, InsType]] = {}
Labels: dict[str, int] = {}
Consts: dict[str, int] = {}


class Command:
    def __init__(self, value: str):
        self.src = value
        self.ins_type: InsType = InsType.Ins_Undef
        self.op: int = 0
        self.op2: int = 0
        self.args: list = None
        self.rd: int = 0
        self.rs1: int = 0
        self.rs2: int = 0
        self.imm: int = 0

    def slice(self):
        if self.src != '':
            self.src = self.src.split(' ')

    def parseOp(self, index: dict):
        if isinstance(self.src, list):
            self.op, self.op2, self.ins_type = index[self.src[0]]
            self.args = self.src[1].split(',')

    def parse_bracket(self):
        if isinstance(self.args, list):
            for i in range(len(self.args)):
                if self.args[i][-1] == ')':
                    self.args[i] = self.args[i][:-1]
                    temp = self.args[i].split('(')
                    if i == 0:
                        self.op2 = int(temp[0])
                        self.args[i] = temp[1]
                    else:
                        self.args.append(temp[0])
                        self.args[i] = temp[1]

    def parse_reg(self, index: dict):
        if isinstance(self.args, list):
            for i in range(len(self.args)):
                match(self.args[i][0]):
                    case 'r' | 'f' | 'd': self.args[i] = int(self.args[i][1:])
                    case _:
                        if self.args[i] in index:
                            self.args[i] = index[self.args[i]]
                        else:
                            pass

    def parse_imm(self):
        if isinstance(self.args, list):
            for i in range(len(self.args)):
                if isinstance(self.args[i], str):
                    if self.args[i].startswith('0x'):
                        self.args[i] = int(self.args[i], 16)
                    elif self.args[i].startswith('0b'):
                        self.args[i] = int(self.args[i], 2)
                    else:
                        self.args[i] = int(self.args[i])

    def mov_vals(self):
        match (self.ins_type):
            case InsType.Ins_R:
                self.rd, self.rs1, self.rs2 = self.args
                self.imm = 0
            case InsType.Ins_I:
                self.rd, self.rs1, self.imm = self.args

    def __int__(self):
        match (self.ins_type):
            case InsType.Ins_R:
                return self.rs2 << 32 | self.rs1 << 24 | self.op2 << 16 | self.rd << 8 | self.op
            case InsType.Ins_I:
                return self.imm << 32 | self.rs1 << 24 | self.op2 << 16 | self.rd << 8 | self.op


class Sector:
    def __init__(self, value: list[str]):
        self.src = value
        self.name: str = None
        self.ins: list[Command] = None
        self.code: list[int] = None
        self.base: int = 0
        self.align: int = 0

    def parse_self(self):
        i = 0
        while i < len(self.src):
            match self.src[i]:
                case '.org':
                    self.base = int(self.src[i].split(' ')[1], 16)
                    self.src.pop(i)
                case '.align':
                    self.align = int(self.src[i].split(' ')[1])
                    self.src.pop(i)
                case '.sector':
                    self.name = self.src[i].split(' ')[1]
                    self.src.pop(i)
                case _:
                    i += 1

    def parse(self, Ins: dict, Labels: dict, Const: dict):
        self.ins = []
        for i in self.src:
            self.ins.append(Command(i))
        length = len(self.ins)
        for i in range(length):
            self.ins[i].slice()
            self.ins[i].parseOp(Ins)
            self.ins[i].parse_bracket()
            self.ins[i].parse_reg(Const)
            self.ins[i].parse_imm()
            self.ins[i].mov_vals()
        self.code = [int(i) for i in self.ins]


def remove_note(src: str) -> str:
    match src[0]:
        case '#' | ';':
            return ''
        case '/':
            match src[1]:
                case '/':
                    return ''
                case _:
                    raise ('SyntaxError: \'/\' is wanted.')
        case _:
            if '#' in src:
                return src.split('#')[0]
            elif ';' in src:
                return src.split(';')[0]
            elif '//' in src:
                return src.split('//')[0]
            else:
                return src


if __name__ == '__main__':
    with open('args.csv', 'r') as f:
        reading = reader(f)
        for i in reading:
            match i[1]:
                case 'Ins_R' | 'Ins_I':
                    Commands[i[0]] = (int(i[2]), int(i[3]), InsType[i[1]])
                case 'Const': Consts[i[0]] = int(i[2])
    source = []
    with open('E:\\Code\\C++\\SandBox3.x\\3.0.x\\3.0.2\\assemble\\lib.vasm', 'r') as f:
        source = f.readlines()
    source = [remove_note(i).rstrip()
              for i in source if remove_note(i) != '']
    source = [i for i in source if i != '']
    pass
